//
//  AWMessage.m
//  AtWork2
//
//  Created by lucas on 15/4/22.
//  Copyright (c) 2015年 Foreveross. All rights reserved.
//

#import "AWMessage.h"
#import "AWAckMessage.h"
#import "AWClientStream.h"
#import "ATWUtil.h"
#import "ATWImApplication.h"

#define Nullable(value) (value != nil ? value : [NSNull null])

#define StringNullable(value) (value != nil ? value : @"")

@interface AWMessage ()

@property (nonatomic, strong, readwrite) NSMutableDictionary *contentBody;

@end

static inline NSString * buildMessageType(AWMessageType type) {
    switch (type) {
        case AWMessageTypeCmd:
            return AWMessageKCmd;
        case AWMessageTypeReq:
            return AWMessageKReq;
        case AWMessageTypeResp:
            return AWMessageKResp;
        case AWMessageTypeAck:
            return AWMessageKAck;
        case AWMessageTypeChat:
            return AWMessageKChat;
        case AWMessageTypeNotice:
            return AWMessageKNotice;
        case AWMessageTypeVoip:
            return AWMessageKVoip;
        case AWMessageTypeServeNo:
            return AWMessageKServeNO;
        case AWMessageTypeCustom:
            return AWMessageKCustom;
    }
}

inline AWMessageType parseWithMessageType(NSString *type) {
    if ([type.uppercaseString isEqualToString:AWMessageKCmd]) {
        return AWMessageTypeCmd;
    }
    if ([type.uppercaseString isEqualToString:AWMessageKReq]) {
        return AWMessageTypeReq;
    }
    if ([type.uppercaseString isEqualToString:AWMessageKResp]) {
        return AWMessageTypeResp;
    }
    if ([type.uppercaseString isEqualToString:AWMessageKAck]) {
        return AWMessageTypeAck;
    }
    if ([type.uppercaseString isEqualToString:AWMessageKChat]) {
        return AWMessageTypeChat;
    }
    if ([type.uppercaseString isEqualToString:AWMessageKNotice]) {
        return AWMessageTypeNotice;
    }
    if ([type.uppercaseString isEqualToString:AWMessageKVoip]) {
        return AWMessageTypeVoip;
    }
    if ([type.uppercaseString isEqualToString:AWMessageKServeNO]) {
        return AWMessageTypeServeNo;
    }
    if ([type.uppercaseString isEqualToString:AWMessageKCustom]) {
        return AWMessageTypeCustom;
    }
    return NSNotFound;
}

inline UInt64 deliveryTime() {
    return [ATWUtil dateOfServerTimestamp];
}

inline NSString * identifier() {
    return [[NSUUID UUID] UUIDString];
}

@implementation AWMessage

+ (instancetype)messageWithFrom:(NSString *)from
                             to:(NSString *)to
                    messageType:(AWMessageType)messageType {
    return [[self alloc] initWithFrom:from to:to messageType:messageType];
}

- (instancetype)initWithFrom:(NSString *)from
                          to:(NSString *)to
                 messageType:(AWMessageType)messageType {
    return [self initWithDeliveryId:identifier() from:from to:to deliveryTime:deliveryTime() messageType:messageType];
}

+ (instancetype)messageWithDeliveryId:(NSString *)deliveryId
                                 from:(NSString *)from
                                   to:(NSString *)to
                         deliveryTime:(UInt64)deliveryTime
                          messageType:(AWMessageType)messageType {
    return [[self alloc] initWithDeliveryId:deliveryId from:from to:to deliveryTime:deliveryTime messageType:messageType];
}

+ (instancetype)messageWithDeliveryId:(NSString *)deliveryId
                                 from:(NSString *)from
                                   to:(NSString *)to
                         deliveryTime:(UInt64)deliveryTime {
    return [[self alloc] initWithDeliveryId:deliveryId from:from to:to deliveryTime:deliveryTime];
}


- (instancetype)initWithDeliveryId:(NSString *)deliveryId
                              from:(NSString *)from
                                to:(NSString *)to
                      deliveryTime:(UInt64)deliveryTime
                       messageType:(AWMessageType)messageType {
    if (self = [self initWithDeliveryId:deliveryId from:from to:to deliveryTime:deliveryTime]) {
        _messageType = messageType;
    }
    return self;
}

- (instancetype)initWithDeliveryId:(NSString *)deliveryId
                              from:(NSString *)from
                                to:(NSString *)to
                      deliveryTime:(UInt64)deliveryTime {
    if (self = [super init]) {
        _deliveryId = [deliveryId copy];
        _from = [from copy];
        _to = [to copy];
        _deliveryTime = deliveryTime;
    }
    return self;
}

- (instancetype)initWithMessageType:(AWMessageType)messageType {
    return [self initWithFrom:@"" to:@"" messageType:messageType];
}

+ (instancetype)messageWithMessageType:(AWMessageType)messageType {
    return [[self alloc] initWithMessageType:messageType];
}

#pragma mark - Public Methods

- (NSData *)buildData {
    return [NSJSONSerialization dataWithJSONObject:@{AWMessageKDeliveryId : self.deliveryId, //Fixed: delivery_id、delivery_time 修改为下划线风格。
                                                     AWMessageKDeliveryTime: @(self.deliveryTime),
                                                     AWMessageKFrom: self.from ?: @"",
                                                     AWMessageKTo: self.to,
                                                     AWMessageKType: buildMessageType(self.messageType),
                                                     AWMessageKBody: [self body]
                                                     }
                                           options:NSJSONWritingPrettyPrinted error:nil];
}

+ (instancetype)messageWithDictionary:(NSDictionary *)aMessage {
    return [[self alloc] initWithDictionary:aMessage];
}

- (instancetype)initWithDictionary:(NSDictionary *)aMessage {
    if (self = [self initWithDeliveryId:aMessage[AWMessageKDeliveryId]
                               from:Nullable(aMessage[AWMessageKFrom])
                                 to:Nullable(aMessage[AWMessageKTo])
                       deliveryTime:[aMessage[AWMessageKDeliveryTime] unsignedLongLongValue]]) {
        self.messageType = parseWithMessageType(aMessage[AWMessageKType]);
        [self.contentBody setDictionary:aMessage[AWMessageKBody]];
    }
    return self;
}

#pragma mark -Private Methods

- (void)bodyWithKey:(NSString *)key value:(id)value {
    [self.contentBody setObject:value forKey:key];
}

- (void)bodyWithOther:(NSDictionary *)other {
    [self.contentBody setDictionary:other];
}

- (void)bodyRemoveWithKey:(NSString *)key {
    [self.contentBody removeObjectForKey:key];
}

- (NSMutableDictionary *)contentBody {
    if (_contentBody == nil) {
        _contentBody = [NSMutableDictionary dictionary];
    }
    return _contentBody;
}

- (id)bodyValueForKey:(NSString *)key {
    return self.contentBody[key];
}

- (NSDictionary *)body {
    return [self.contentBody copy];
}

- (void)send {
    [[ATWImApplication sharedInstance].stream sendMessage:self];
}

#pragma mark - Override NSObject Methods

- (NSUInteger)hash {
    return self.deliveryId.hash;
}

- (BOOL)isEqual:(id)object {
    if (object == self) {
        return YES;
    }
    
    if (!object || ![object isKindOfClass:[self class]]) {
        return NO;
    }
    
    AWMessage *that = (AWMessage *)object;
    
    if ([ATWUtil isEmpty:self.deliveryId] ||
        [ATWUtil isEmpty:that.deliveryId]) {
        return NO;
    }
    
    if([self.deliveryId isEqualToString:that.deliveryId]) {
        return YES;
    }
    return NO;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"<%@: %p %@>",
            self.class,
            self,
            @{ @"deliveryId": self.deliveryId }];
}

- (NSString *)debugDescription {
    return [NSString stringWithFormat:@"<%@: %p deliveryId = %@>",
            self.class,
            self,
            @{ @"from": self.from,
               @"to": self.to,
               @"body": [self body],
               @"deliveryId": self.deliveryId,
               @"deliveryTime": @(self.deliveryTime),
               @"messageType": buildMessageType(self.messageType) }];
}
@end